home *** CD-ROM | disk | FTP | other *** search
- function su_Prefetcher()
- {
- //!!! We need to get the mouse cursor load clock image to not spin.
- // background:
- // The cursor is set by the docshell's progress listener implementation.
- // http://lxr.mozilla.org/seamonkey/source/docshell/base/nsDocShell.cpp#4778
- // http://lxr.mozilla.org/aviary101branch/source/docshell/base/nsDocShell.cpp#4537
-
- //### private attributes
- var service;
- try {
- service = Components.classes["@stumbleupon.com/stumbleupon-service;1"].getService().wrappedJSObject;
- }
- catch (e) {
- // seamonkey kludge
- service = su_service;
- }
- this.ds = service.getDatastore();
- this.URIsIndex = -1;
- this.URIs = new Array();
- this.referrersByURI = new Object();
- this.redirectTargetsByURI = new Object();
- this.passCountsByURI = new Object();
- this.statesByURI = new Object();
- this.urlDetailByURI = new Object();
- this.httpStatusesByURI = new Object();
- this.target = null;
- this.id = su_Prefetcher.instanceCount++;
- this.browserId = "su_prefetcher" + this.id;
- this.passCount = 1;
- this.URIsTopIndex = 0;
- this.URIsBottomIndex = -1;
- this.eventListenerListsByEventId = new Object();
- this.queueLocked = false;
-
- //### public attributes
-
- this.mode = "complete";
- this.pass1TimeoutInterval = 10000;
- this.pass2TimeoutInterval = 30000;
- this.pass3TimeoutInterval = 120000;
- this.passMax = 3;
- this.disabled = false;
- this.delayedStartInterval = 0;
- this.pauseForScriptRedirectInterval = 800;
- this.continuous = true;
- this.maintainHistory = false;
- this.allTargetsPrefetched = true;
- this.fetchAheadDepth = -1;
-
- //### private methods
-
- this._start = function()
- {
- if (this.disabled)
- return;
- if (this.allTargetsPrefetched)
- return;
-
- var browser = document.getElementById(this.browserId);
- if (browser)
- {
- this._logRedirectTarget();
-
- document.getElementById("main-window").removeChild(browser);
- }
-
- var found = false;
- var uri;
- while ((! found) && ((this.URIsIndex + 1) <= this.URIsBottomIndex))
- {
- this.URIsIndex++;
- uri = this.URIs[this.URIsIndex];
- if ((this.statesByURI[uri] == "new") ||
- ((this.passCount > 1) && (this.passCountsByURI[uri] > 1) &&
- (this.passCountsByURI[uri] < this.passMax) &&
- (this.statesByURI[uri] == "timed-out")))
- {
- found = true;
- }
- }
- if (! found)
- {
- this.passCount++;
- if (this.passCount > this.passMax)
- {
- this.target = null;
- this.allTargetsPrefetched = true;
- this._dispatchEvent("done");
- if (this.ds.getValue("@log_prefetch_progress"))
- su_log("prefetching done");
- }
- else if (! this.allTargetsPrefetched)
- {
- this.target = null;
- this.URIsIndex = this.URIsTopIndex - 1;
- this._start();
- }
- return;
- }
-
- this.target = uri;
-
- // The technique of deleting/creating a browser each time and
- // applying to it the style attribute below is derived from the
- // Cooliris extension with permission from its developers. -- JW
- browser = document.createElement("browser");
- browser.setAttribute("id", this.browserId);
- browser.setAttribute("type", "content");
- browser.setAttribute("src", "about:blank");
- browser.setAttribute("style", "visibility:hidden;overflow:auto;border:0px solid black;background-color:white;width:0px;height:0px;");
-
- document.getElementById("main-window").appendChild(browser);
-
- browser.docShell.allowJavascript = true;
- browser.docShell.allowMetaRedirects = true;
- browser.docShell.allowAuth = false;
- browser.docShell.allowPlugins = false;
- browser.docShell.allowSubframes = true;
-
- if (this.mode == "DOM")
- {
- browser.addEventListener("DOMContentLoaded", function () { this.handleDocumentLoad("DOMContentLoaded"); }, true);
- }
- browser.addProgressListener(this);
-
- try {
- browser.loadURI(this.target, su_get_nsiuri(this.referrersByURI[this.target]), null);
- } catch (e) {
- su_log_error("prefetch load error", e, this.target);
- }
-
- // if (browser.contentDocument.contentType != "text/html")
- // {
- // browser.stop();
- // this.URIsIndex++;
- // this._start();
- // }
-
- var interval;
- switch (this.passCountsByURI[this.target])
- {
- case 1: interval = this.pass1TimeoutInterval; break;
- case 2: interval = this.pass2TimeoutInterval; break;
- case 3: interval = this.pass3TimeoutInterval; break;
- }
-
- if (this.ds.getValue("@log_prefetch_progress"))
- su_log("prefetching " + (this.URIsIndex + 1) + " of " + this.URIs.length, this.target, "pass " + this.passCount + " with timeout " + interval + "ms");
-
- this.timer = setTimeout(function (prefetcher) { prefetcher._finishPrefetch("timeout"); }, interval, this)
- }
-
- this._finishPrefetch = function (from)
- {
- if (this.ds.getValue("@log_prefetch_progress"))
- su_log("finish", from);
- var state;
- switch (from)
- {
- case "timeout": state = "timed-out"; break;
- case "pause":
- case "stop":
- case "advance": state = "new"; break;
- case "skip": state = "skipped"; break;
- case "load": state = "fetched"; break;
- }
- this.statesByURI[this.target] = state;
-
- if (this.timer)
- {
- clearTimeout(this.timer);
- }
- if (this.pauseForScriptRedirectTimer)
- {
- clearTimeout(this.pauseForScriptRedirectTimer);
- }
-
- if ((from == "load") || (from == "timeout"))
- this.passCountsByURI[this.target]++;
-
- if (from == "stop")
- {
- var browser = document.getElementById(this.browserId);
- if (browser)
- {
- document.getElementById("main-window").removeChild(browser);
- }
- }
-
- if ((from == "pause") && (from == "stop"))
- return;
-
- if (this.continuous)
- {
- setTimeout(function (prefetcher) { prefetcher._start(); }, this.pauseForScriptRedirectInterval, this);
- }
- else
- {
- this._logRedirectTarget();
- this.pauseForScriptRedirectTimer = setTimeout(function (prefetcher) { prefetcher._logRedirectTarget; }, this.pauseForScriptRedirectInterval, this);
- }
- }
-
- this._logRedirectTarget = function ()
- {
- if (! this.target)
- return;
-
- if (this.ds.getValue("@log_prefetch_progress"))
- su_log("logging " + (this.URIsIndex + 1) + " of " + this.URIs.length, this.target, "pass " + this.passCount, "state " + this.statesByURI[this.target]);
-
- var browser = document.getElementById(this.browserId);
- if (browser && browser.contentDocument && browser.contentDocument.location)
- {
- this.redirectTargetsByURI[this.target] = browser.contentDocument.location.href;
- }
- }
-
- this._updateBottomIndex = function ()
- {
- if (this.fetchAheadDepth == -1)
- {
- this.URIsBottomIndex = this.URIs.length - 1;
- }
- else
- {
- this.URIsBottomIndex = this.URIsTopIndex + this.fetchAheadDepth - 1;
- if (this.URIsBottomIndex > this.URIs.length - 1)
- {
- this.URIsBottomIndex = this.URIs.length - 1;
- }
- }
- }
-
- this._dispatchEvent = function (eventId)
- {
- var listeners = this.eventListenerListsByEventId[eventId];
- if (! listeners)
- return;
-
- var i;
- for (i = 0; i < listeners.length; i++)
- {
- var event = new Object();
- event.target = this;
- listeners[i](event);
- }
- }
-
-
- //### privileged methods
-
- this.handleDocumentLoad = function (from)
- {
- var browser = document.getElementById(this.browserId);
- if ((((from == "DOMContentLoaded") && (this.mode == "DOM")) ||
- ((from == "progress-stop") && (this.mode == "complete"))) &&
- browser && browser.contentDocument &&
- browser.contentDocument.location &&
- (browser.contentDocument.location.href != "about:blank"))
- {
- this._finishPrefetch("load");
- }
- }
-
- this.setQueueLock = function (state)
- {
- this.queueLocked = state;
- }
-
- this.addTarget = function (urlDetail)
- {
- if (this.queueLocked)
- return;
-
- if (! this.statesByURI[urlDetail.url])
- {
- this.urlDetailByURI[urlDetail.url] = urlDetail;
- this.statesByURI[urlDetail.url] = "new";
- this.allTargetsPrefetched = false;
- this.URIs.push(urlDetail.url);
- this.passCount = 1;
- this.passCountsByURI[urlDetail.url] = 1;
- this._updateBottomIndex();
- this.referrersByURI[urlDetail.url] = urlDetail.referrer;
- }
- }
-
- this.skipCurrentTarget = function ()
- {
- this._finishPrefetch("skip");
- }
-
- this.advancePastTarget = function (uri)
- {
- var i;
- this._finishPrefetch("advance");
- for (i = 0; i < this.URIs.length; i++)
- {
- if (this.URIs[i] == uri)
- {
- if (i >= this.URIsBottomIndex)
- {
- this.allTargetsPrefetched = true;
- break;
- }
- else
- {
- this.passCount = 1;
- this.allTargetsPrefetched = false;
- this.URIsTopIndex = i + 1;
- if (this.URIsIndex < this.URIsTopIndex)
- {
- this.URIsIndex = this.URIsTopIndex;
- }
- this._updateBottomIndex();
- }
- }
- }
- }
-
- this.clearTargets = function ()
- {
- this.URIsIndex = -1;
- this.allTargetsPrefetched = true;
- this.URIs = new Array();
- if (! this.maintainHistory)
- {
- this.clearHistory();
- }
- }
-
- this.clearHistory = function ()
- {
- this.passCountsByURI = new Object();
- this.redirectTargetsByURI = new Object();
- this.statesByURI = new Object();
- this.referrersByURI = new Object();
- this.httpStatusesByURI = new Object();
- this.urlDetailByURI = new Object();
- }
-
- this.getRedirectTarget = function (uri)
- {
- var target = this.redirectTargetsByURI[uri];
- return (target) ? target : uri;
- }
-
- this.setRedirectTarget = function (originalTarget, currentTarget)
- {
- this.redirectTargetsByURI[originalTarget] = currentTarget;
- }
-
- this.getCurrentTarget = function ()
- {
- return this.target;
- }
-
- this.setHttpResponseStatus = function (target, status)
- {
- var prev = parseInt(this.httpStatusesByURI[target]);
- var cur = parseInt(status);
- if ((! prev) || (prev > cur))
- this.httpStatusesByURI[target] = status;
- }
-
- this.getHttpResponseStatus = function (target)
- {
- return (this.httpStatusesByURI[target]) ? this.httpStatusesByURI[target] : null;
- }
-
- this.start = function ()
- {
- this.disabled = false;
- setTimeout(function (prefetcher) { prefetcher._start(); }, this.delayedStartInterval, this);
- }
-
- this.stop = function ()
- {
- this.disabled = true;
- this._finishPrefetch("stop");
- this.target = null;
- this.URIsIndex = -1;
- }
-
- this.pause = function ()
- {
- this.disabled = true;
- this._finishPrefetch("pause");
- if ((this.URIsIndex >= this.URIsTopIndex) && (! this.allTargetsPrefetched))
- {
- this.URIsIndex--;
- }
- }
-
- this.addEventListener = function (eventId, listener)
- {
- var listeners = this.eventListenerListsByEventId[eventId];
- if (! listeners)
- {
- listeners = new Array();
- this.eventListenerListsByEventId[eventId] = listeners;
- }
- else
- {
- this.removeEventListener(eventId, listener);
- }
- listeners.push(listener);
- }
-
- this.removeEventListener = function (eventId, listener)
- {
- var listeners = this.eventListenerListsByEventId[eventId];
- var i;
- for (i = 0; i < listeners.length; i++)
- {
- if (listener == listeners[i])
- {
- listeners = listeners.splice(i, 1);
- break;
- }
- }
- }
-
- this.QueryInterface = function (iid)
- {
- if (!iid.equals(Components.interfaces.nsIWebProgressListener) &&
- !iid.equals(Components.interfaces.nsISupportsWeakReference) && // not implemented
- !iid.equals(Components.interfaces.nsISupports))
- {
- throw Components.errors.NS_ERROR_NO_INTERFACE;
- }
-
- return this;
- }
-
- this.onLocationChange = function (aWebProgress, aRequest, aLocation) {}
-
- this.onProgressChange = function (aWebProgress, aRequest,
- aCurSelfProgress, aMaxSelfProgress,
- aCurTotalProgress, aMaxTotalProgress)
- {
- window.setCursor("auto");
- setTimeout(function (window) { window.setCursor("auto"); }, 0, window);
- }
-
- this.onStateChange = function(aWebProgress, aRequest, aStateFlags, aStatus)
- {
- const nsIWPL = Components.interfaces.nsIWebProgressListener;
- var originalUrl;
-
- window.setCursor("auto");
- setTimeout(function (window) { window.setCursor("auto"); }, 0, window);
-
- if (! (aStateFlags & nsIWPL.STATE_IS_REQUEST))
- return;
-
- if (aStateFlags & nsIWPL.STATE_START)
- {
- // Kill alert and prompt on prefetch pages. -- JW
- var win;
- if (aWebProgress.DOMWindow.wrappedJSObject)
- win = aWebProgress.DOMWindow.wrappedJSObject;
- else
- win = aWebProgress.DOMWindow;
-
- win.alert = function (){};
- win.prompt = function (){};
- win.confirm = function (){};
- win.open = function (){};
- win.moveTo = function (){};
- win.resizeTo = function (){};
- win.sizeToContent = function (){};
-
- this._dispatchEvent("progress-start");
- }
-
- try {
- if (aWebProgress.DOMWindow != aWebProgress.DOMWindow.top)
- return;
- } catch (e) { return; } // ignore error accessing DOMWindow.top
-
- if (aStateFlags & nsIWPL.STATE_STOP)
- {
- try {
- var browser = document.getElementById(this.browserId);
- var channel = browser.docShell.currentDocumentChannel;
-
- var status = channel.responseStatus;
- this.setHttpResponseStatus(this.target, status);
- } catch (e) {}
- // Notify the prefetcher that the document load is complete.
- this.handleDocumentLoad("progress-stop");
- }
- }
-
- this.onStatusChange = function (aWebProgress, aRequest, aStatus, aMessage)
- {
- window.setCursor("auto");
- setTimeout(function (window) { window.setCursor("auto"); }, 0, window);
- }
-
- this.onSecurityChange = function (aWebProgress, aRequest, aState) {}
- }
- //### static attributes
- su_Prefetcher.instanceCount = 0;
-
-